#pragma once
#include <brpc/server.h>
#include <butil/logging.h>
#include "asr.hpp"      // 语音识别模块封装
#include "etcd.hpp"     // 服务注册模块封装
#include "logger.hpp"   // 日志模块封装
#include "speech.pb.h"  // protobuf框架代码


namespace zzy_mims
{
    class SpeechServiceImpl : public zzy_mims::SpeechService 
    {
    public:
        SpeechServiceImpl(const ASRClient::ptr& asr_client):_asr_client(asr_client){};
        ~SpeechServiceImpl(){};
        void SpeechRecognition(google::protobuf::RpcController* controller,
        const ::zzy_mims::SpeechRecognitionReq* request, 
        ::zzy_mims::SpeechRecognitionRsp* response, 
        ::google::protobuf::Closure* done)//相当于以请求和回应的方式对asr.hpp的再一次封装
        {
            LOG_DEBUG("收到语音转文字请求！");
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            std::string err;
            std::string res = _asr_client->recognize(request->speech_content(),err);
            if(res.empty())
            { 
                LOG_ERROR("{}语音识别失败!",request->request_id());
                response->set_request_id(request->request_id());
                response->set_success(false);
                response->set_errmsg("语音识别失败:"+err);
                return;
            }
            response->set_request_id(request->request_id());
            response->set_success(true);
            response->set_errmsg(res);
        }

    private:
        ASRClient::ptr _asr_client;
    };

    class SpeechServer//speech的rpc服务器,用来通过rpc来调用服务 
    {
    public:
        using ptr = std::shared_ptr<SpeechServer>;
        SpeechServer(const ASRClient::ptr asr_client,
        const Registery::ptr reg_client,
        std::shared_ptr<brpc::Server> server):
        _asr_client(asr_client),_reg_client(reg_client),_rpc_server(server)
        {};
        ~SpeechServer(){};
        void start()
        {
            _rpc_server->RunUntilAskedToQuit();
        }

    private:
        ASRClient::ptr _asr_client;
        Registery::ptr _reg_client;
        std::shared_ptr<brpc::Server> _rpc_server;

    };
    class  SpeechServerBuilder//给出构建一个SpeechServer的规范方法
    {
    public:
    ~SpeechServerBuilder(){};
    //构造语音识别客户端对象
    void make_asr_object(const std::string& app_id,
    const std::string& api_key,const std::string& secret_key)
    {
        _asr_client= std::make_shared<ASRClient>(app_id,api_key,secret_key);
    }
    //用于构造服务注册客户端对象
    void make_reg_object(const std::string& reg_host,
    const std::string& service_name,
    const std::string& access_host)
    {
        _reg_client = std::make_shared<Registery>(reg_host);
        _reg_client->Register(service_name,access_host);
    }
     //构造RPC服务器对象
    void make_rpc_server(uint16_t port,int32_t timeout,uint8_t num_threads)
    {
        if(!_asr_client)
        {
             LOG_ERROR("还未初始化语音识别模块！");
            abort();
        }
        _rpc_server = std::make_shared<brpc::Server>();
        SpeechServiceImpl* speech_service = new SpeechServiceImpl(_asr_client);
        int ret = _rpc_server->AddService(speech_service,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
        if(ret==-1)
        {
            LOG_ERROR("添加RPC服务失败!");
            abort();
        }
        brpc::ServerOptions options;
        options.idle_timeout_sec=timeout;
        options.num_threads = num_threads;
        ret = _rpc_server->Start(port,&options);
        if(ret==-1)
        {
            LOG_ERROR("speech_RPC服务器启动失败");
            abort();
        }
    }
    SpeechServer::ptr build()
    {
        if (!_asr_client) 
        {
            LOG_ERROR("还未初始化语音识别模块！");
            abort();
        }
        if (!_reg_client) {
            LOG_ERROR("还未初始化服务注册模块！");
            abort();
        }
        if (!_rpc_server) {
            LOG_ERROR("还未初始化RPC服务器模块！");
            abort();
        }
        SpeechServer::ptr server = std::make_shared<SpeechServer>(_asr_client, _reg_client, _rpc_server);
        return server;
    }
    private:
        ASRClient::ptr _asr_client;
        Registery::ptr _reg_client;
        std::shared_ptr<brpc::Server> _rpc_server;
    };
};